package com.yanqu.road.server.manger.messagesubscribe;

import com.yanqu.road.entity.enums.eChannelType;
import com.yanqu.road.entity.enums.eMessageSubscribeType;
import com.yanqu.road.entity.hunt.HuntTimeData;
import com.yanqu.road.entity.messageSubscribe.entity.*;
import com.yanqu.road.entity.messageSubscribe.entity.messageParam.*;
import com.yanqu.road.entity.player.PlayerState;
import com.yanqu.road.entity.player.UserInfo;
import com.yanqu.road.logic.bussiness.message.MessageSubscribeBussiness;
import com.yanqu.road.logic.config.ChannelConfig;
import com.yanqu.road.pb.messagesubscribe.MessageSubscribe;
import com.yanqu.road.server.GameServer;
import com.yanqu.road.server.TempMgr;
import com.yanqu.road.server.gameplayer.GamePlayer;
import com.yanqu.road.server.manger.ConfigMgr;
import com.yanqu.road.server.manger.ServerListMgr;
import com.yanqu.road.server.manger.messagesubscribe.enums.MessageSubscribeConfig;
import com.yanqu.road.server.manger.player.GamePlayerMgr;
import com.yanqu.road.server.manger.player.UserMgr;
import com.yanqu.road.server.protocol.Protocol;
import com.yanqu.road.utils.ConfigHelper;
import com.yanqu.road.utils.date.DateHelper;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 消息订阅
 *
 * @Description
 * @Author cwq
 * @Data 2023/5/6 12:04
 */
public class MessageSubscribeMgr extends TempMgr {

    private static Logger logger = LogManager.getLogger(MessageSubscribeMgr.class);

    /**
     * 玩家订阅消息信息 k:playerId
     */
    private static Map<String, ChannelTemplateInfo> channelTemplateInfoMap = new ConcurrentHashMap<>();
    /**
     * 玩家订阅消息信息 k:playerId
     */
    private static Map<Long, MessageSubscribePlayerData> playerSubscribeMap = new ConcurrentHashMap<>();


    public static Map<Long, MessageUserNoticeData> userNoticeDataMap = new ConcurrentHashMap<>();

    public static Map<String, ChannelTemplateInfo> getChannelTemplateInfoMap() {
        return channelTemplateInfoMap;
    }



    public static MessageUserNoticeData getUserNoticeData(long userId){
        synchronized (userNoticeDataMap){
            if(!userNoticeDataMap.containsKey(userId)){
                MessageUserNoticeData noticeData = MessageSubscribeBussiness.getMessageUserNotice(userId);
                if(noticeData == null){
                    noticeData = new MessageUserNoticeData();
                    noticeData.setUserId(userId);
                    noticeData.setLastUpdateTime(System.currentTimeMillis());
                    noticeData.setInsertOption();
                }
                userNoticeDataMap.put(userId,noticeData);
            }
        }
        return userNoticeDataMap.get(userId);
    }

    // TODO 线程池


    public static void setSubscribe(long userId ,String tempId,boolean gameOpen,boolean wxOpen){
        MessageSubscribePlayerData playerData = getUserData(userId);
        if(playerData == null){
            return;
        }
        Map<String, MessageSubscribeInfo> sbMap = playerData.getSubscribedMap();
        if(sbMap.containsKey(tempId)){
            MessageSubscribeInfo sbInfo = sbMap.get(tempId);
            sbInfo.setIsSubscribeOfGame(gameOpen);
            sbInfo.setTouchTime(System.currentTimeMillis());
            sbInfo.setIsSubscribeOfWx(wxOpen);
        }else{
            MessageSubscribeInfo sbInfo = new MessageSubscribeInfo();
            sbInfo.setUserId(userId);
            sbInfo.setTemplateId(tempId);
            sbInfo.setIsSubscribeOfGame(gameOpen);
            sbInfo.setIsSubscribeOfWx(wxOpen);
            sbInfo.setTouchTime(System.currentTimeMillis());
            sbMap.put(sbInfo.getTemplateId(),sbInfo);
        }
        playerData.setSubscribedMap(sbMap);
    }

    public static MessageSubscribePlayerData getUserData(long userId){
        if(!playerSubscribeMap.containsKey(userId)){
            initPlayerSubscribeMap(userId);
        }
        return playerSubscribeMap.get(userId);
    }

    private static void initPlayerSubscribeMap(long userId){
        synchronized (playerSubscribeMap){
            if(!playerSubscribeMap.containsKey(userId)){
                MessageSubscribePlayerData playerData = new MessageSubscribePlayerData();
                playerData.setPlayerId(userId);
                playerData.setOpenId("");
                playerData.setInsertOption();
                playerSubscribeMap.put(userId,playerData);
            }
        }
    }

    public static void testSend(String openId){
        GameServer.getSqlCommandExecutor().execute(() -> {
            try {
//                MessageSubscribeMgr.sendMessageSubscribe(MessageSubscribeConfig.OfflineReward, openId, new OfflineRewardData(new WxMessageSubscribeValue("离线收益已满，掌柜请前往领取"), new WxMessageSubscribeValue("资源刷新")));
            } catch (Exception e) {
                GamePlayerMgr.getLogger().error("wechat sendMessage error.",e);
            }
        });
    }


    @Override
    public boolean save() {
        for(MessageSubscribePlayerData playerData : new ArrayList<>(playerSubscribeMap.values())){
            if(playerData.isInsertOption()){
                MessageSubscribeBussiness.addMessageSubscribe(playerData);
            }else if(playerData.isUpdateOption()){
                MessageSubscribeBussiness.updateMessageSubscribe(playerData);
            }
        }

        for(MessageUserNoticeData noticeData : new ArrayList<>(userNoticeDataMap.values())){
            if(noticeData.isInsertOption()){
                MessageSubscribeBussiness.addMessageUserNotice(noticeData);
            }else if(noticeData.isUpdateOption()){
                MessageSubscribeBussiness.updateMessageUserNotice(noticeData);
            }
        }
        return true;
    }

    private void reloadUserData(){
        playerSubscribeMap = MessageSubscribeBussiness.getMessageSubscribeMap();
        long dateTime = System.currentTimeMillis() - DateHelper.DAY_MILLIONS * 7;
        userNoticeDataMap = MessageSubscribeBussiness.getMessageUserNoticeMap(dateTime);
    }

    @Override
    public boolean init() throws Exception {
        long serverId = ConfigHelper.getLong("serverId");
        int channelId = ServerListMgr.getChannelId(serverId);
//        if(channelId == 301 || channelId == 701){
//            checkMessageSubscribeConfig();
//        }
        reloadUserData();
        channelTemplateInfoMap = MessageSubscribeBussiness.getChannelTemplateMap(channelId);
        return true;
    }


    public boolean reloadConfig() throws Exception {
        long serverId = ConfigHelper.getLong("serverId");
        int channelId = ServerListMgr.getChannelId(serverId);
//        if(channelId == 301 || channelId == 701){
//            checkMessageSubscribeConfig();
//        }
        reloadUserData();
        channelTemplateInfoMap = MessageSubscribeBussiness.getChannelTemplateMap(channelId);
        if(channelId == 701){
            logger.error("测试发送消息");
//            MessageSubscribeMgr.sendMessageSubscribe(MessageSubscribeConfig.OfflineReward, "oFuDZ5Hh12nZqeARW5QcG9NCVK00", new OfflineRewardData(new WxMessageSubscribeValue("离线收益已满，掌柜请前往领取"), new WxMessageSubscribeValue("资源刷新")));
            GameServer.getSqlCommandExecutor().execute(() -> {
                try {
                    MessageSubscribePlayerData data = new MessageSubscribePlayerData();
                    data.setPlayerId(999999950000007L);
                    MessageSubscribeMgr.sendMessageWx(MessageSubscribeConfig.OfflineReward, data,
                            new OfflineRewardData(new WxMessageSubscribeValue("离线收益已满，掌柜请前往领取"), new WxMessageSubscribeValue("资源刷新")));
                } catch (Exception e) {
                    GamePlayerMgr.getLogger().error("wechat sendMessage error.",e);
                }
            });
        }
        return true;
    }

    @Override
    public boolean reloadData() throws Exception {
        return true;
    }

    @Override
    public boolean stop() {
        return true;
    }




//    /**
//     * 发送微信订阅消息 (需要异步调用)
//     *
//     * @param templateConfig
//     * @param openId
//     */
//    public static void sendMessageSubscribe(MessageSubscribeConfig templateConfig, String openId, IWxMessageSubscribeData data) {
//        if (openId.isEmpty()) {
//            return;
//        }
//        StackTraceElement[] elements = Thread.currentThread().getStackTrace();
//        String methodName = elements[2].getMethodName();
//        //下面的main可以直接发
//        if (!methodName.equals("main") && !isWxSwitch()) {
//            return;
//        }
//        try {
//            String accessToken = getAccessToken();
//            if (StringUtils.isNullOrEmpty(accessToken)) {
//                return;
//            }
//            String url = ChannelConfig.WEICHAT_SEND_NOTICE_URL;
//            if(url == null){
//                url = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=";
//            }
//            url = url + accessToken;
//            JSONObject paramObj = new JSONObject();
//            paramObj.put("template_id", templateConfig.getWxTemplateId());
//            paramObj.put("page", "index");
//            paramObj.put("touser", openId);
//            paramObj.put("data", data);
//            paramObj.put("miniprogram_state", "formal");
//            paramObj.put("lang", "zh_CN");
//            String result = HttpHelper.doPostJson(url, paramObj.toJSONString(), "UTF-8");
//            if (null == result) {
//                logger.info("发送微信订阅消息 异常。 url:{}, paramObj:{}", url, paramObj.toJSONString());
//                return;
//            }
//            logger.info("发送微信订阅消息 result:{}", result);
//            JSONObject resultObject = JSONObject.parseObject(result);
//            if (resultObject.getIntValue("errcode") != 0) {
//                logger.warn("发送订阅消息 {}  失败 templateId:{}, openId:{}", templateConfig.getGameTitle(), templateConfig.getWxTemplateId(), openId);
//            }
//        } catch (Exception e) {
//            logger.error("发送订阅消息异常 templateId:{}, openId:{}", templateConfig.getWxTemplateId(), openId, e);
//        }
//    }


//    /**
//     * 对比 MessageSubscribeConfig 与微信的配置
//     *
//     * @return
//     */
//    private boolean checkMessageSubscribeConfig() {
//        if (!isWxSwitch()) {
//            return true;
//        }
//        String accessToken = getAccessToken();
//        if (StringUtils.isNullOrEmpty(accessToken)) {
//            return false;
//        }
//        // TODO 地址看看配哪里
//        String url = ChannelConfig.WEICHAT_SEND_NOTICE_URL;
//        Map<String, String> paramMap = new HashMap<>();
//        paramMap.put("access_token", accessToken);
//        Map<String, String> resultMap = HttpHelper.doGet(url, paramMap);
//        if (null == resultMap) {
//            logger.info("获取微信订阅模板 异常。 url:{}, paramMap:{}", url, paramMap);
//            return false;
//        }
//        logger.info("获取微信订阅模板 code:{}; result:{}", resultMap.get("code"), resultMap.get("body"));
//        String body = resultMap.get("body");
//        JSONObject jsonObject = JSONObject.parseObject(body);
//        if (jsonObject.getIntValue("errcode") == 0) {
//            String data = jsonObject.getString("data");
//            JSONArray dataArray = JSONObject.parseArray(data);
//
//            Map<String, JSONObject> objectMap = new HashMap<>();
//            for (int i = 0; i < dataArray.size(); i++) {
//                String str = dataArray.getString(i);
//                logger.debug("微信模板 :{}", str);
//                JSONObject object = JSONObject.parseObject(str);
//                String priTmplId = object.getString("priTmplId");
//
//                objectMap.put(priTmplId, object);
//                MessageSubscribeConfig config = MessageSubscribeConfig.forNumber(priTmplId);
//                if (config == null) {
//                    logger.warn("从微信获取的订阅模板，在游戏服找不到 priTmplId：{}", priTmplId);
//                }
//            }
//            for (MessageSubscribeConfig config : MessageSubscribeConfig.values()) {
//                JSONObject object = objectMap.get(config.getWxTemplateId());
//                if (object == null) {
//                    config.setInWxTemplate(false);
//                    logger.warn("区服配置的模板id,在微信中未找到 priTmplId：{}", config.getWxTemplateId());
//                    continue;
//                }
//                String title = object.getString("title");
//                int type = object.getIntValue("type");
//                String content = object.getString("content");
//
//                if (config.getType().getValue() != type) {
//                    config.setType(MessageSubscribeType.forNumber(type));
//                }
//                config.setInWxTemplate(true);
//            }
//            return true;
//        }
//        logger.error("获取微信订阅模板失败");
//        return false;
//    }

//    private static String getAccessToken() {
//        try {
//            // TODO 地址看看配哪里
//            String url = ChannelConfig.WEICHAT_ACCESS_TOKEN_URL;
//            if(url == null){
//                url = "https://apipay.shxnetwork.com/paygate.php?c=wxmp&a=wx_tk";
//            }
//            int game_id = 788;
//            long time = System.currentTimeMillis() / 1000;
//            String key = ChannelConfig.WEICHAT_TOKEN_KEY;
//            if(key == null){
//                key = "2PNpY6u80b5BivyoMthW9aVUlrFj1z4Q";
//            }
//            StringBuffer sb = new StringBuffer();
//            sb.append(game_id).append(time).append(key);
//            String sign = MD5Security.md5(sb.toString()).toLowerCase();
//
//            SortedMap<String, String> paramMap = new TreeMap<>();
//            paramMap.put("game_id", String.valueOf(game_id));
//            paramMap.put("unsafe", String.valueOf(1));
//            paramMap.put("time", String.valueOf(time));
//            paramMap.put("sign", sign);
//            String result = HttpHelper.doPost(url, paramMap, "UTF-8");
//            JSONObject jsonObject = JSONObject.parseObject(result);
//            if (jsonObject.containsKey("code") && jsonObject.getIntValue("code") == 1) {
//                return jsonObject.getString("data");
//            }
//            logger.info("获取 AccessToken 失败。 url:{},paramMap:{}, result:{}", url, JSON.toJSONString(paramMap), result);
//        } catch (Exception e) {
//            logger.error("获取 AccessToken 失败。", e);
//        }
//        return "";
//    }

    /**
     * 是否开启这个功能
     *
     * @return
     */
    public static boolean isSwitch() {
        // TODO 判断渠道号、是否是正式环境
        long serverId = ConfigHelper.getLong("serverId");
        int channelId = ServerListMgr.getChannelId(serverId);
        if(channelId == 301
                || channelId == 701
                || channelId == eChannelType.Mobile_DY.getValue()
                || channelId == eChannelType.Mobile_ZFB.getValue()){
            return true;
        }
        return false;
    }

    public static boolean isWxSwitch() {
        // TODO 判断渠道号、是否是正式环境
        long serverId = ConfigHelper.getLong("serverId");
        int channelId = ServerListMgr.getChannelId(serverId);
        if(channelId == 301 || channelId == 701){
            return true;
        }
        return false;
    }

    public static void setOffLineTime(long userId,long currTime){
        MessageSubscribePlayerData playerData = getUserData(userId);
        if(playerData != null){
            playerData.setOffLineTime(currTime);
        }
    }

    //定时发
    public static void timerTask() {
        String dateStr = DateHelper.getCurrentDateTimeString();
        long nowTime = System.currentTimeMillis();
        Map<Long, MessageSubscribePlayerData> dataMap = new ConcurrentHashMap<>(playerSubscribeMap);
        for(MessageSubscribePlayerData playerData : dataMap.values()){
//            if(playerData.getOpenId().equals("") || !playerData.isSwitch()){
            if(playerData.getOpenId().equals("") && playerData.getAppExt().isEmpty()){
                continue;
            }

            boolean isSave = false;
            Map<String, String> dyData = new HashMap<>();
            Map<String, MessageSubscribeInfo> sbMap = playerData.getSubscribedMap();
            for(MessageSubscribeInfo sbInfo : sbMap.values()){
                if(sbInfo.isSubscribeOfGame()){
                    MessageSubscribeConfig config = MessageSubscribeConfig.forNumber(sbInfo.getTemplateId());
                    if(config == null){
                        logger.info("{}出现没有的模板{}",sbInfo.getUserId(),sbInfo.getTemplateId());
                        continue;
                    }
                    if(config == MessageSubscribeConfig.OfflineReward){
                        if(nowTime - playerData.getOffLineTime() * 1000 >= ChannelConfig.OFFLINE_REWARD_TIME * 1000 &&
                                nowTime - sbInfo.getTouchTime() >= ChannelConfig.OFFLINE_REWARD_TIME * 1000 ){
                            sendMessageWx(config,playerData,
                                    new OfflineRewardData(
                                            new WxMessageSubscribeValue("离线收益已满，掌柜请前往领取"),
                                            new WxMessageSubscribeValue("资源刷新")));
                            dyData.clear();
                            dyData.put("资源刷新", "离线收益已满，掌柜请前往领取");
                            sendMessageDy(config, playerData, dyData);
                            sendMessageZfb(config, playerData, dyData);
                            sbInfo.setTouchTime(nowTime);
                            //发完一次就要取消订阅了
                            sbInfo.setIsSubscribeOfGame(false);
                            syncUser(playerData,sbInfo);
                            isSave = true;
                        }
                    }else if(config == MessageSubscribeConfig.NoonHuntTime){
                        HuntTimeData huntTimeData = ConfigMgr.getHuntTimeData();
                        if(huntTimeData == null){
                            continue;
                        }
                        long noticeTime = DateHelper.getTodayZeroTimeStamp() + huntTimeData.getStartHour() * DateHelper.HOUR_MILLIONS +
                                huntTimeData.getStarMinute() * DateHelper.MINUTE_MILLIONS;
                        MessageUserNoticeData noticeData = getUserNoticeData(playerData.getPlayerId());
                        noticeData.setNoonHuntTime(noticeTime);
                        if(nowTime >= noticeData.getNoonHuntTime() && noticeData.getNoonHuntTime() > sbInfo.getTouchTime()){
                            sendMessageWx(config,playerData,
                                    new NoonHuntTimeData(
                                            new WxMessageSubscribeValue(dateStr),
                                            new WxMessageSubscribeValue("古林狩猎已开启，掌柜快与门客一同前往！")));
                            dyData.clear();
                            dyData.put(dateStr, "古林狩猎已开启，掌柜快与门客一同前往！");
                            sendMessageDy(config, playerData, dyData);
                            sendMessageZfb(config, playerData, dyData);
                            sbInfo.setTouchTime(nowTime);
                            sbInfo.setIsSubscribeOfGame(false);
                            syncUser(playerData,sbInfo);
                            isSave = true;
                        }
                    }else{
                        MessageUserNoticeData noticeData = getUserNoticeData(playerData.getPlayerId());
                        IWxMessageSubscribeData data = null;
                        long time = 0;
                        switch (config){
                            case SonRecovery:
                                time = noticeData.getSonTime();
                                data = new SonRecoveryData(
                                        new WxMessageSubscribeValue("徒弟培养提醒"),
                                        new WxMessageSubscribeValue("徒弟活力均已恢复，快来培养徒弟吧"));
                                dyData.clear();
                                dyData.put("徒弟培养提醒", "徒弟活力均已恢复，快来培养徒弟吧");
                                break;
                            case MistressRecovery:
                                time = noticeData.getMistressTime();
                                data = new MistressRecoveryData(
                                        new WxMessageSubscribeValue("挚友谈心提醒"),
                                        new WxMessageSubscribeValue("挚友谈心次数已达上限，快来与挚友谈心吧！"));
                                dyData.clear();
                                dyData.put("挚友谈心提醒", "挚友谈心次数已达上限，快来与挚友谈心吧！");
                                break;
                            case HospitalRecovery:
                                time = noticeData.getHospitalTime();
                                data = new HospitalRecoveryData(
                                        new WxMessageSubscribeValue("0"),
                                        new WxMessageSubscribeValue("医馆病人排号达到上限，来为病人诊治吧！"));
                                dyData.clear();
                                dyData.put("0", "医馆病人排号达到上限，来为病人诊治吧！");
                                break;
                            case TravelRecovery:
                                time = noticeData.getTravelTime();
                                data = new TravelRecoveryData(
                                        new WxMessageSubscribeValue("外出游历提醒"),
                                        new WxMessageSubscribeValue("掌柜体力已达上限，何不外出，游历四方！"));
                                dyData.clear();
                                dyData.put("外出游历提醒", "掌柜体力已达上限，何不外出，游历四方！");
                                break;
                            case PatronsWarSilverRecovery:
                                time = noticeData.getPatronsWarSilverTime();
                                data = new PatronsWarSilverRecoveryData(
                                        new WxMessageSubscribeValue(dateStr),
                                        new WxMessageSubscribeValue("税所收益已达上限，请掌柜及时收取！"));
                                dyData.clear();
                                dyData.put(dateStr, "税所收益已达上限，请掌柜及时收取！");
                                break;
                            case ClinicRecovery:
                                time = noticeData.getClinicTime();
                                data = new ClinicRecoveryData(
                                        new WxMessageSubscribeValue(dateStr),
                                        new WxMessageSubscribeValue("药铺病人排号达到上限，来为病人诊治吧！"));
                                dyData.clear();
                                dyData.put(dateStr, "药铺病人排号达到上限，来为病人诊治吧！");
                                break;
                            case BussinessPosRob:
                                time = noticeData.getBussinessPosRobTime();
                                data = new BussinessPosRobData(
                                        new WxMessageSubscribeValue("招商被占提醒"),
                                        new WxMessageSubscribeValue("掌柜招商项目被收购！"));
                                dyData.clear();
                                dyData.put("招商被占提醒", "掌柜招商项目被收购！");
                                break;
                            case ManorFoodRecovery:
                                time = noticeData.getManorFoodTime();
                                data = new ManorFoodRecoveryData(
                                        new WxMessageSubscribeValue(dateStr),
                                        new WxMessageSubscribeValue("庄园作物存储已达上限，请掌柜及时收取！"));
                                dyData.clear();
                                dyData.put(dateStr, "庄园作物存储已达上限，请掌柜及时收取！");
                                break;
                            case WineShopRecovery:
                                time = noticeData.getWineShopTime();
                                data = new WineShopRecoveryData(
                                        new WxMessageSubscribeValue("酒肆叫号提醒"),
                                        new WxMessageSubscribeValue("酒肆客人排号达到上限，快来接待客人吧！"));
                                dyData.clear();
                                dyData.put("酒肆叫号提醒", "酒肆客人排号达到上限，快来接待客人吧！");
                                break;
                            case UnionCampWarTime:
                            case MonopolyTime:
                                eMessageSubscribeType eMSType = config.geteMSType();
                                if (eMSType == null)
                                {
                                    continue;
                                }
                                List<Long> timeList = noticeData.getSubTime(eMSType);
                                if(null == timeList){
                                    continue;
                                }
                                for (long timeTemp : timeList) {
                                    if (nowTime >= timeTemp && timeTemp > sbInfo.getTouchTime()) {
                                        GamePlayer player = GamePlayerMgr.getOnlinePlayer(playerData.getPlayerId());
                                        if (player == null || player.getState() != PlayerState.ONLINE) {
                                            time = timeTemp;
                                            break;
                                        } else {
                                            sbInfo.setTouchTime(nowTime);
                                            sbInfo.setIsSubscribeOfGame(false);
                                            syncUser(playerData,sbInfo);
                                            isSave = true;
                                            break;
                                        }
                                    }
                                }
                                data = new TimeTipActivityData(
                                        new WxMessageSubscribeValue(eMSType.getGameTitle()),
                                        new WxMessageSubscribeValue(eMSType.getGameContent()));
                                dyData.clear();
                                dyData.put(eMSType.getGameTitle(), eMSType.getGameContent());
                                break;
                            case KuangBattleTime:
                            case XiuXianTime:
                            case DouLuoTime:
                            case FengShenTime:
                            case JiuZhouApplyTime:
                            case JiuZhouBattleTime:
                            case DaoMuTime:
                                eMessageSubscribeType eMSTypeData = config.geteMSType();
                                if (eMSTypeData == null)
                                {
                                    continue;
                                }
                                List<Long> timeListData = noticeData.getSubTime(eMSTypeData);
                                if(null == timeListData){
                                    continue;
                                }
                                for (long timeTemp : timeListData) {
                                    if (nowTime >= timeTemp && timeTemp > sbInfo.getTouchTime()) {
                                        GamePlayer player = GamePlayerMgr.getOnlinePlayer(playerData.getPlayerId());
                                        if (player == null || player.getState() != PlayerState.ONLINE) {
                                            time = timeTemp;
                                            break;
                                        } else {
                                            sbInfo.setTouchTime(nowTime);
                                            sbInfo.setIsSubscribeOfGame(false);
                                            syncUser(playerData,sbInfo);
                                            isSave = true;
                                            break;
                                        }
                                    }
                                }
                                data = new TimeTipData(
                                        new WxMessageSubscribeValue(eMSTypeData.getGameTitle()),
                                        new WxMessageSubscribeValue(eMSTypeData.getGameContent()));
                                dyData.clear();
                                dyData.put(eMSTypeData.getGameTitle(), eMSTypeData.getGameContent());
                                break;
                        }
                        if(nowTime >= time && time > sbInfo.getTouchTime()){
                            sendMessageWx(config,playerData,data);
                            sendMessageDy(config, playerData, dyData);
                            sendMessageZfb(config, playerData, dyData);
                            sbInfo.setTouchTime(nowTime);
                            sbInfo.setIsSubscribeOfGame(false);
                            syncUser(playerData,sbInfo);
                            isSave = true;
                        }
                    }
                }

            }
            if(isSave){
                playerData.setSubscribedMap(sbMap);
            }
        }
    }

    private static void sendMessageWx(MessageSubscribeConfig config, MessageSubscribePlayerData playerData, IWxMessageSubscribeData wxData) {
        GameServer.getSqlCommandExecutor().execute(() -> {
            try {
                if (playerData == null) {
                    return;
                }
                UserInfo userInfo = UserMgr.getUserInfo(playerData.getPlayerId());
                if (userInfo == null) {
                    return;
                }
                WxMessageSubscribe.sendMessageSubscribe(config, userInfo.getPlatformUserId(), wxData, false);
            } catch (Exception e) {
                GamePlayerMgr.getLogger().error("offline report error.", e);
            }
        });
    }

    private static void sendMessageDy(MessageSubscribeConfig config, MessageSubscribePlayerData playerData, Map<String, String> dyData){
        GameServer.getSqlCommandExecutor().execute(() -> {
            try {
                if (playerData == null) {
                    return;
                }
                UserInfo userInfo = UserMgr.getUserInfo(playerData.getPlayerId());
                if (userInfo == null) {
                    return;
                }
                DyMessageSubscribe.sendMessageSubscribe(config, playerData.getAppExt(), userInfo.getPlatformUserId(), dyData, false);
            } catch (Exception e) {
                GamePlayerMgr.getLogger().error("offline report error.",e);
            }
        });
    }

    private static void sendMessageZfb(MessageSubscribeConfig config, MessageSubscribePlayerData playerData, Map<String, String> dyData){
        GameServer.getSqlCommandExecutor().execute(() -> {
            try {
                if (playerData == null) {
                    return;
                }
                UserInfo userInfo = UserMgr.getUserInfo(playerData.getPlayerId());
                if (userInfo == null) {
                    return;
                }
                Map<String, Map<String, String>> zfbData = new HashMap<>();
                zfbData.put("keyword1", new HashMap<>());
                zfbData.put("keyword2", new HashMap<>());
                for (Map.Entry<String, String> entry : dyData.entrySet()) {
                    zfbData.get("keyword1").put("value", entry.getKey());
                    zfbData.get("keyword2").put("value", entry.getValue());
                }
                ZfbMessageSubscribe.sendMessageSubscribe(config, playerData.getAppExt(), userInfo.getPlatformUserId(), zfbData, false);
            } catch (Exception e) {
                GamePlayerMgr.getLogger().error("offline report error.",e);
            }
        });
    }

    private static void syncUser(MessageSubscribePlayerData playerData,MessageSubscribeInfo sbInfo){
        GamePlayer onlinePlayer = GamePlayerMgr.getOnlinePlayer(playerData.getPlayerId());
        if(onlinePlayer != null){
            MessageSubscribe.MessageSubscribeBroadcast.Builder syncMsg = MessageSubscribe.MessageSubscribeBroadcast.newBuilder();
            MessageSubscribe.MessageSubscribeData.Builder sbInfoMsg = MessageSubscribe.MessageSubscribeData.newBuilder();
            sbInfoMsg.setTemplateId(sbInfo.getTemplateId());
            sbInfoMsg.setIsSubscribeOfGame(sbInfo.isSubscribeOfGame());
            sbInfoMsg.setIsSubscribeOfWx(sbInfo.isSubscribeOfWx());
            onlinePlayer.sendPacket(Protocol.U_MESSAGE_SUBSCRIBE_BROADCAST, syncMsg);
        }
    }

    // 测试
    public static void main(String[] args) {
        String dateStr = DateHelper.getCurrentDateTimeString();
        //离线收益
//        MessageSubscribeMgr.sendMessageSubscribe(MessageSubscribeConfig.OfflineReward, "oFuDZ5FDDp6ECTGgllfgTIibx_YA", new OfflineRewardData(new WxMessageSubscribeValue(dateStr), new WxMessageSubscribeValue("银两收益存储已达上限，请掌柜及时收取！")));
//        MessageSubscribeMgr.sendMessageSubscribe(MessageSubscribeConfig.OfflineReward, "oFuDZ5Hh12nZqeARW5QcG9NCVK00", new OfflineRewardData(new WxMessageSubscribeValue("离线收益已满，掌柜请前往领取"), new WxMessageSubscribeValue("资源刷新")));

        //徒弟培养提醒
//        MessageSubscribeMgr.sendMessageSubscribe(MessageSubscribeConfig.SonRecovery, "oFuDZ5FDDp6ECTGgllfgTIibx_YA", new SonRecoveryData(new WxMessageSubscribeValue("徒弟培养提醒"), new WxMessageSubscribeValue("徒弟活力均已恢复，快来培养徒弟吧")));

        MessageSubscribeConfig config = MessageSubscribeConfig.MistressRecovery;
        IWxMessageSubscribeData wxData = null;
        Map<String, String> dyData = new HashMap<>();
        Map<String, Map<String, String>> zfbData = new HashMap<>();
        switch (config){
            case SonRecovery:
                wxData = new SonRecoveryData(
                        new WxMessageSubscribeValue("徒弟培养提醒"),
                        new WxMessageSubscribeValue("徒弟活力均已恢复，快来培养徒弟吧"));
                dyData.clear();
                dyData.put("徒弟培养提醒", "徒弟活力均已恢复，快来培养徒弟吧");
                break;
            case MistressRecovery:
                wxData = new MistressRecoveryData(
                        new WxMessageSubscribeValue("挚友谈心提醒"),
                        new WxMessageSubscribeValue("挚友谈心次数已达上限，快来与挚友谈心吧！"));
                dyData.clear();
                dyData.put("挚友谈心提醒", "挚友谈心次数已达上限，快来与挚友谈心吧！");
                zfbData.clear();
                zfbData.put("keyword1", new HashMap<>());
                zfbData.put("keyword2", new HashMap<>());
                for (Map.Entry<String, String> entry : dyData.entrySet()) {
                    zfbData.get("keyword1").put("value", entry.getKey());
                    zfbData.get("keyword2").put("value", entry.getValue());
                }
                break;
            case HospitalRecovery:
                wxData = new HospitalRecoveryData(
                        new WxMessageSubscribeValue("0"),
                        new WxMessageSubscribeValue("医馆病人排号达到上限，来为病人诊治吧！"));
                dyData.clear();
                dyData.put("0", "医馆病人排号达到上限，来为病人诊治吧！");
                break;
            case TravelRecovery:
                wxData = new TravelRecoveryData(
                        new WxMessageSubscribeValue("外出游历提醒"),
                        new WxMessageSubscribeValue("掌柜体力已达上限，何不外出，游历四方！"));
                dyData.clear();
                dyData.put("外出游历提醒", "掌柜体力已达上限，何不外出，游历四方！");
                break;
            case PatronsWarSilverRecovery:
                wxData = new PatronsWarSilverRecoveryData(
                        new WxMessageSubscribeValue(dateStr),
                        new WxMessageSubscribeValue("税所收益已达上限，请掌柜及时收取！"));
                dyData.clear();
                dyData.put(dateStr, "税所收益已达上限，请掌柜及时收取！");
                break;
            case ClinicRecovery:
                wxData = new ClinicRecoveryData(
                        new WxMessageSubscribeValue(dateStr),
                        new WxMessageSubscribeValue("药铺病人排号达到上限，来为病人诊治吧！"));
                dyData.clear();
                dyData.put(dateStr, "药铺病人排号达到上限，来为病人诊治吧！");
                break;
            case BussinessPosRob:
                wxData = new BussinessPosRobData(
                        new WxMessageSubscribeValue("招商被占提醒"),
                        new WxMessageSubscribeValue("掌柜招商项目被收购！"));
                dyData.clear();
                dyData.put("招商被占提醒", "掌柜招商项目被收购！");
                break;
            case ManorFoodRecovery:
                wxData = new ManorFoodRecoveryData(
                        new WxMessageSubscribeValue(dateStr),
                        new WxMessageSubscribeValue("庄园作物存储已达上限，请掌柜及时收取！"));
                dyData.clear();
                dyData.put(dateStr, "庄园作物存储已达上限，请掌柜及时收取！");
                break;
            case WineShopRecovery:
                wxData = new WineShopRecoveryData(
                        new WxMessageSubscribeValue("酒肆叫号提醒"),
                        new WxMessageSubscribeValue("酒肆客人排号达到上限，快来接待客人吧！"));
                dyData.clear();
                dyData.put("酒肆叫号提醒", "酒肆客人排号达到上限，快来接待客人吧！");
                break;
            case NoonHuntTime:
                wxData = new WineShopRecoveryData(
                        new WxMessageSubscribeValue(dateStr),
                        new WxMessageSubscribeValue("古林狩猎已开启，掌柜快与门客一同前往！"));
                dyData.clear();
                dyData.put(dateStr, "古林狩猎已开启，掌柜快与门客一同前往！");
                break;
            case UnionCampWarTime:
            case MonopolyTime:
                eMessageSubscribeType eMSType = config.geteMSType();
                if (eMSType == null)
                {
                    break;
                }
                wxData = new TimeTipActivityData(
                        new WxMessageSubscribeValue(eMSType.getGameTitle()),
                        new WxMessageSubscribeValue(eMSType.getGameContent()));
                dyData.clear();
                dyData.put(eMSType.getGameTitle(), eMSType.getGameContent());
                break;
            case KuangBattleTime:
            case XiuXianTime:
            case DouLuoTime:
            case FengShenTime:
            case JiuZhouApplyTime:
            case JiuZhouBattleTime:
            case DaoMuTime:
                eMessageSubscribeType eMSTypeData = config.geteMSType();
                if (eMSTypeData == null) {
                    break;
                }
                wxData = new TimeTipData(
                        new WxMessageSubscribeValue(eMSTypeData.getGameTitle()),
                        new WxMessageSubscribeValue(eMSTypeData.getGameContent()));
                dyData.clear();
                dyData.put(eMSTypeData.getGameTitle(), eMSTypeData.getGameContent());
                break;
        }

        if (wxData != null) {
            // platformUserId 为数字
            WxMessageSubscribe.sendMessageSubscribe(config, "2174483313", wxData, false);
            DyMessageSubscribe.sendMessageSubscribe(config, "eyJhcHBpZCI6InR0ZTcxODkxYTU3ODI2N2Y3NjAyIiwib3BlbmlkIjoiZTlkNzIyMTctNzkzMS00YzA1LWEzMGMtMjQ5MzZkZTJiZTc5IiwidW5pb25pZCI6IjQzNDg3NmFlLTM5ZjItNDdiZC04NTM1LWQwNTNjZDA1ZjU3MiIsInNlc3Npb25fa2V5IjoiYmMwMTN0NTZsR2RHZlNpSEUwWDh6ZGJOa013K2puT3pPd2N5WmpjU2RHalIzU3ozczlvdU9GdlZDN0RFMjNHZFlYTWh5bXciLCJhbm9ueW1vdXNfb3BlbmlkIjoiIiwiaXNfbmV3IjowLCJ3eF9wYXJhbSI6IntcImFpZFwiOlwiMjMyOVwiLFwiYXBwSWRcIjpcInR0ZTcxODkxYTU3ODI2N2Y3NjAyXCIsXCJtcFZlcnNpb25cIjpcIjYuNi4xXCIsXCJzY2VuZVwiOlwiMTAyMDAxXCIsXCJyZWZlcmVyXCI6XCJoYXh5eHRmX2cxX3htdF9hbmRyb2lkX2R5emxsXCJ9Iiwic3FfZ2FtZV9pZCI6Ijg0MyIsInN1YnNjcmliZV90bXBscyI6WyJNU0cxMzI0NTIxMzNhYTczNWZhOWViMTY2ZDExNTI3ZGE2NTQ2YjdlNTMxMzcxNSJdLCJoZF9zdGltZSI6MTcxNDM2MTgzMCwiaGRfc2lnbiI6IjZhZTQxNTc2Y2FhNDI4NGEiLCJpbml0X2ZjbSI6eyJteXJuIjoxLCJ4d3NtIjoiMCIsInhmY24iOiIwIn0sImFwcF9wc3QiOiJNMlptTVV3dk5XcDNaWGt3WVhOQlVtTllLM0V5VVdkWlIwWXJVM1ExYkhJemFEQk1RamwzT1hCTlQzSkdWWEpCYzNSb2FIbEZVV2xyWlhwaE5USndkUzkwTlZsNlp6QmlMek5wVlZaWGNrUm1URXBwTjFadFdIUnBaMUI1UVhrclNtUnZTek4yVW1oUVJtY3hNVGhYYW05UmVtc3Zia1pSYjB4clRGVjZOWEkxWkVneWRtcDJRalZ0YUVWemRXNVdZMlZFVmpWU2JYWTVWa3N5ZG5NeGQxRTFWMEY1T1VndmJEaFFhWHB0Ynpaa0wwaE1Na05NYW1ZeWJ6aGlVSEZHV1hGTVNGZEVSMWRzVmpCMlZFZFdkbGhpU3k5Q1F6aHphbnAxVTNGWFpYVTNOQzlIYkM5bU9IUlJWVlZ6UlZwSlIzSloiLCJfcGFkXyI6Il9fXyJ9", "2298915437", dyData, false);
            ZfbMessageSubscribe.sendMessageSubscribe(config, "eyJhcHBpZCI6IjIwMjEwMDQxMjI2MjcwMjIiLCJvcGVuaWQiOiIwOTZ4TmpsN0Z0bUlWUUFaV0U4S0xDQmlNRGhGWnJLZTFXMnQtaHdZeEhCamhvMiIsInVuaW9uaWQiOiIwOTYzdjl0bWd2aVJaQlBFdmR5MDI4a0oyT294blRhRDN4VjZBb0NEMVZFR05RMCIsImlzX25ldyI6MCwid3hfcGFyYW0iOiJ7fSIsInd4X3N5c3RlbV9pbmZvIjoie1wibW9kZWxcIjpcIkhVQVdFSSBKQUQtQUw1MFwiLFwicGl4ZWxSYXRpb1wiOjMuMzc1LFwicGxhdGZvcm1cIjpcIkFuZHJvaWRcIixcInNjcmVlbkhlaWdodFwiOjI3MDAsXCJzY3JlZW5XaWR0aFwiOjEyMjgsXCJzeXN0ZW1cIjpcIjEwXCIsXCJ2ZXJzaW9uXCI6XCIxMC41LjkwLjgwMDBcIixcIndpbmRvd0hlaWdodFwiOjgwMCxcIndpbmRvd1dpZHRoXCI6MzYzLFwibGFuZ3VhZ2VcIjpcIlwiLFwiaXNJcGhvbmVYU2VyaWVzXCI6ZmFsc2V9Iiwic3FfZ2FtZV9pZCI6IjkzMSIsImlzX29pZCI6MSwiaGRfc3RpbWUiOjE3MTQzNjQwNjYsImhkX3NpZ24iOiIyOTUzNmI5ZTQzZDY0ZjQ4IiwiaW5pdF9mY20iOnsibXlybiI6MSwieHdzbSI6IjAiLCJ4ZmNuIjoiMCJ9LCJhcHBfcHN0IjoiTldOaVltMWpOU3RpWW5SRVlXdzRaM1pyVERCWVJrdzBSMVJ2Tnk5RWVVMTVLMk51TW5WUlptMUJXRFoxZEU1UFpGSTJORmRTZUhGNFZITjRWVFpKY1hOWE5FRTJPVzlUVkhCcmNXaHNLMUZHWkhWTmVIcHVhQzl5YUZsM1JtNHZSazlzZDNOVE5rVXphRE4zYjBwUFFuQllaVWsyTm5sRWN6aDVkRWx5U0RGUFNsVkVhbEl6VTJwV00xSk5VMXBNZWxoS2VqWXdZWFpKWVc0dlp6QkhibXAyWkZCWGR6WlNjbFY0TkhnMWRVWjBORVp1SzBGT1IyRkdiSEoxYlhSbGFtNVhjVkp0U0VVelV6WkJSMlF4VW5wMFdrbHpUVFpvY2tSSVRubFBWMHh0Y3pORGNqUXJUR05xVVRCSU5tMTNTREpwVmc9PSJ9", "2814925533", zfbData, false);
        }
//        MessageSubscribeMgr.sendMessageSubscribe(MessageSubscribeConfig.GameUpdate, "oFuDZ5FDDp6ECTGgllfgTIibx_YA", new GameUpdateData(new WxMessageSubscribeValue("2022年9月4日"), new WxMessageSubscribeValue("活动开启")));
    }
}
